package com.hdu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hdu.entity.TeachPlan;
import com.hdu.entity.TeachPlanMedia;
import com.hdu.exception.BizException;
import com.hdu.mapper.TeachPlanMapper;
import com.hdu.mapper.TeachPlanMediaMapper;
import com.hdu.service.ITeachPlanService;
import com.hdu.vo.BindTeachPlanMediaVo;
import com.hdu.vo.TeachPlanVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class TeachPlanServiceImpl extends ServiceImpl<TeachPlanMapper, TeachPlan> implements ITeachPlanService {

    private final TeachPlanMapper teachplanMapper;

    private final TeachPlanMediaMapper teachplanMediaMapper;

    @Override
    public List<TeachPlanVo> findTeachPlanTree(Long courseId) {
        return teachplanMapper.selectTreeNodes(courseId);
    }

    @Transactional
    @Override
    public void saveTeachPlan(TeachPlan teachPlan) {
        Long teachPlanId = teachPlan.getId();
        if (teachPlanId == null) {
            // 课程计划id为null，创建对象，拷贝属性，设置创建时间和排序号
            TeachPlan plan = new TeachPlan();
            BeanUtils.copyProperties(teachPlan, plan);
            plan.setCreateDate(LocalDateTime.now());
            // 设置排序号
            plan.setOrderBy(getTeachPlanCount(plan.getCourseId(), plan.getParentId()) + 1);
            // 如果新增失败，返回0，抛异常
            int flag = teachplanMapper.insert(plan);
            if (flag <= 0) throw new BizException("新增失败");
        } else {
            // 课程计划id不为null，查询课程，拷贝属性，设置更新时间，执行更新
            TeachPlan plan = teachplanMapper.selectById(teachPlanId);
            BeanUtils.copyProperties(teachPlan, plan);
            plan.setChangeDate(LocalDateTime.now());
            // 如果修改失败，返回0，抛异常
            int flag = teachplanMapper.updateById(plan);
            if (flag <= 0) throw new BizException("修改失败");
        }
    }

    @Transactional
    @Override
    public void deleteTeachPlan(Long teachPlanId) {
        if (teachPlanId == null)
            throw new BizException("课程计划id为空");
        TeachPlan teachplan = teachplanMapper.selectById(teachPlanId);
        // 判断当前课程计划是章还是节
        Integer grade = teachplan.getGrade();
        // 当前课程计划为章
        if (grade == 1) {
            // 查询当前课程计划下是否有小节
            LambdaQueryWrapper<TeachPlan> queryWrapper = new LambdaQueryWrapper<>();
            // select * from teachPlan where parentId = {当前章计划id}
            queryWrapper.eq(TeachPlan::getParentId, teachPlanId);
            // 获取一下查询的条目数
            int count = Math.toIntExact(teachplanMapper.selectCount(queryWrapper));
            // 如果当前章下还有小节，则抛异常
            if (count > 0)
                throw new BizException("课程计划信息还有子级信息，无法操作");
            teachplanMapper.deleteById(teachPlanId);
        } else {
            // 课程计划为节，删除改小节课程计划
            teachplanMapper.deleteById(teachPlanId);
            // 条件构造器
            LambdaQueryWrapper<TeachPlanMedia> queryWrapper = new LambdaQueryWrapper<>();
            // 删除媒资信息中对应teachPlanId的数据
            queryWrapper.eq(TeachPlanMedia::getTeachPlanId, teachPlanId);
            teachplanMediaMapper.delete(queryWrapper);
        }
    }

    @Transactional
    @Override
    public void orderByTeachPlan(String moveType, Long teachPlanId) {
        TeachPlan teachplan = teachplanMapper.selectById(teachPlanId);
        // 获取层级和当前order，章节移动和小节移动的处理方式不同
        Integer grade = teachplan.getGrade();
        Integer order = teachplan.getOrderBy();
        // 章节移动是比较同一课程id下的order
        Long courseId = teachplan.getCourseId();
        // 小节移动是比较同一章节id下的order
        Long parentId = teachplan.getParentId();
        if ("up".equals(moveType)) {
            if (grade == 1) {
                // 章节上移，找到上一个章节的order，然后与其交换order
                LambdaQueryWrapper<TeachPlan> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TeachPlan::getGrade, 1)
                        .eq(TeachPlan::getCourseId, courseId)
                        .lt(TeachPlan::getOrderBy, order)
                        .orderByDesc(TeachPlan::getOrderBy)
                        .last("limit 1");
                TeachPlan tmp = teachplanMapper.selectOne(queryWrapper);
                exchangeOrder(teachplan, tmp);
            } else if (grade == 2) {
                // 小节上移
                LambdaQueryWrapper<TeachPlan> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TeachPlan::getParentId, parentId)
                        .lt(TeachPlan::getOrderBy, order)
                        .orderByDesc(TeachPlan::getOrderBy)
                        .last("LIMIT 1");
                TeachPlan tmp = teachplanMapper.selectOne(queryWrapper);
                exchangeOrder(teachplan, tmp);
            }

        } else if ("down".equals(moveType)) {
            if (grade == 1) {
                // 章节下移
                LambdaQueryWrapper<TeachPlan> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TeachPlan::getCourseId, courseId)
                        .eq(TeachPlan::getGrade, grade)
                        .gt(TeachPlan::getOrderBy, order)
                        .orderByAsc(TeachPlan::getOrderBy)
                        .last("LIMIT 1");
                TeachPlan tmp = teachplanMapper.selectOne(queryWrapper);
                exchangeOrder(teachplan, tmp);
            } else if (grade == 2) {
                // 小节下移
                LambdaQueryWrapper<TeachPlan> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TeachPlan::getParentId, parentId)
                        .gt(TeachPlan::getOrderBy, order)
                        .orderByAsc(TeachPlan::getOrderBy)
                        .last("LIMIT 1");
                TeachPlan tmp = teachplanMapper.selectOne(queryWrapper);
                exchangeOrder(teachplan, tmp);
            }
        }
    }

    @Override
    public TeachPlan getTeachPlan(Long teachPlanId) {
        return teachplanMapper.selectById(teachPlanId);
    }

    @Transactional
    @Override
    public void associationMedia(BindTeachPlanMediaVo bindTeachPlanMediaVo) {
        Long teachPlanId = bindTeachPlanMediaVo.getTeachPlanId();
        // 先根据请求参数查询出对应的教学计划teachPlan
        TeachPlan teachplan = teachplanMapper.selectById(teachPlanId);
        if (teachplan == null) {
            throw new BizException("教学计划不存在");
        }
        // 获取教学计划的层级，只有第二层级允许绑定媒资信息（第二层级为小节，第一层级为章节）
        Integer grade = teachplan.getGrade();
        if (grade != 2) {
            throw new BizException("只有小节允许绑定媒资信息");
        }
        // 绑定媒资，如果之前已经绑定过了媒资，再次绑定时为更新（例如该小节已经绑定了 星际牛仔.avi，现在改绑为 胶水.avi，其实现方式为先删再增）
        LambdaQueryWrapper<TeachPlanMedia> queryWrapper = new LambdaQueryWrapper<TeachPlanMedia>().eq(TeachPlanMedia::getTeachPlanId, teachPlanId);
        // 先删
        teachplanMediaMapper.delete(queryWrapper);
        // 再增
        TeachPlanMedia teachplanMedia = new TeachPlanMedia();
        teachplanMedia.setTeachPlanId(bindTeachPlanMediaVo.getTeachPlanId());
        teachplanMedia.setMediaFilename(bindTeachPlanMediaVo.getFileName());
        teachplanMedia.setMediaId(bindTeachPlanMediaVo.getMediaId());
        teachplanMedia.setCourseId(teachplan.getCourseId());
        teachplanMedia.setCreateDate(LocalDateTime.now());
        teachplanMediaMapper.insert(teachplanMedia);
    }

    @Override
    public void unAssociationMedia(Long teachPlanId, String mediaId) {
        LambdaQueryWrapper<TeachPlanMedia> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TeachPlanMedia::getTeachPlanId, teachPlanId)
                .eq(TeachPlanMedia::getMediaId, mediaId);
        teachplanMediaMapper.delete(queryWrapper);
    }

    /**
     * 交换两个TeachPlan的order
     *
     * @param teachPlan teachPlan1
     * @param tmp       teachPlan2
     */
    private void exchangeOrder(TeachPlan teachPlan, TeachPlan tmp) {
        if (tmp == null)
            throw new BizException("已经到头啦，不能再移啦");
        else {
            // 交换order，更新
            Integer order = teachPlan.getOrderBy();
            Integer tmpOrder = tmp.getOrderBy();
            teachPlan.setOrderBy(tmpOrder);
            tmp.setOrderBy(order);
            teachplanMapper.updateById(tmp);
            teachplanMapper.updateById(teachPlan);
        }
    }

    private int getTeachPlanCount(Long courseId, Long parentId) {

        LambdaQueryWrapper<TeachPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TeachPlan::getCourseId, courseId);
        queryWrapper.eq(TeachPlan::getParentId, parentId);
        return Math.toIntExact(teachplanMapper.selectCount(queryWrapper));
    }
}
